#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include <vector>
#include <GL/glew.h>
#include <GL/glut.h>
#include <glm/glm.hpp>

#include "ObjFileReader.h"

MayaObject* readObjFile(const char* filename){
  printf(" reading obj file: %s\n", filename);
  std::string str, cmd ; 
  std::ifstream in ;
  in.open(filename) ; 
  if (in.is_open()) {
	  getline(in, str);

      int line = 1;
	  MayaObject * obj = new MayaObject();

      while (in) {
        if ((str.find_first_not_of(" \t\r\n") != std::string::npos) && (str[0] != '#')) {
	        std::stringstream s(str) ;
		    s >> cmd ; 
			bool validinput = true;
			
			//printf("line %d: ", line);
			//std::cout << cmd << "\n";

			if( cmd == "v"){
				glm::vec4 v(0,0,0,1.0f);
				for(int i = 0; i<4; i++){
					 s >> v[i];
					 if( s.fail() && (i==3)){
						v[3] = 1.0f; //v[3] is 1.0 if not specified
					 }else if (s.fail()){
						printf("%d: failed v command: not enough vertices\n", line);
						validinput = false;
					 }
				}
				//printf("v: %.2f,%.2f,%.2f,%.2f\n", v[0],v[1],v[2],v[3]);
				if( validinput){
					obj->addVector(v);
				}
			}// end parse "v"
			else if (cmd == "f"){
				std::string expr;
				std::vector<GLint> facev;
				std::vector<GLint> normv;

				while( 1){//loop until s.fail()
					s >> expr;			
					if( s.fail()){ //if no more arguments, break out of loop
						//printf(" done.\n");
						break;
					}
					GLint face, text, norm;
					face = text = norm = -1; //-1 represents "not specified"
					parseFace(expr, &face, &text, &norm);
					//printf("%d/%d/%d ", face,text,norm);

					if( face==-1){
						printf("%d: Error: Face not specified. Skipping face\n", line);
						validinput = false;
						break;
					}
					if( norm== -1){
						norm = face;//when a norm vertex is not specified, use the face vector index.
					}
					if( (text!= -1) ){
						//printf("%d: Warning: texture for faces not implemented. Ignoring\n", line);
					}
					normv.push_back(norm);
					facev.push_back(face);
				}//end while
				if( facev.size() < 3){
					printf("%d: Error: A face must have at least 3 vertices\n", line);		
					validinput = false;
				}
				if( validinput){
					obj->addNormIndex(normv);
					obj->addFace(facev);
				}
			}// end parse "f"
			else if ( cmd == "vn"){
				glm::vec3 norm(0,0,0);
				for(int i = 0; i<3; i++){
					 s >> norm[i];
					 if (s.fail()){
						printf("%d: failed vn command: not enough coordinates\n", line);
						validinput = false;
					 }
				}
				//printf("%d vn: %.2f,%.2f,%.2f\n",line, norm[0],norm[1],norm[2]);
				if( validinput){
					obj->addNormVect(norm);
				}
			}
			else if ( cmd == "s" || cmd == "g" || cmd == "vt"){
			//do nothing
			}
			else{
				std::cout << "Unkown .obj command: " << cmd << ". Skipping\n";
			}

	    }
		getline(in, str);
		line++;
	  }

	  return obj;

  }else{
	  printf("Cannot open .obj file: %s\n", filename);
	  return NULL;
  }
}

/**
	Parses an element in the "f" command
	expr will be a string in the format face/texture/norm
**/
void parseFace( std::string expr, int* face, int* texture, int* norm){
	std::stringstream ss(expr);
	std::string cheese;

	int i = 0;
	while( getline( ss, cheese, '/')){
		//printf("c: %s\n", cheese.c_str());
		if( cheese.size() <1){
			continue;
		}
		if( i==0){
			*face = std::stoi(cheese);
		}else if (i==1){
			*texture = std::stoi(cheese);
		}else if (i==2){
			*norm = std::stoi(cheese);
		}else{
			printf("error: f command is not in the format face/texture/norm\n");
			break;
		}
		i++;
	}
}